package com.whacos.modules.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.whacos.common.entity.Tree;
import com.whacos.common.exception.BDException;
import com.whacos.common.shiro.ShiroUtils;
import com.whacos.common.utils.BuildTree;
import com.whacos.common.utils.FileUtils;
import com.whacos.common.utils.ImageUtils;
import com.whacos.common.utils.MD5Utils;
import com.whacos.common.utils.ObjectUtils;
import com.whacos.common.utils.StringUtils;
import com.whacos.modules.system.dao.SysDeptDao;
import com.whacos.modules.system.dao.SysUserDao;
import com.whacos.modules.system.dao.SysUserPlusDao;
import com.whacos.modules.system.dao.SysUserRoleDao;
import com.whacos.modules.system.entity.SysDept;
import com.whacos.modules.system.entity.SysUser;
import com.whacos.modules.system.entity.SysUserPlus;
import com.whacos.modules.system.entity.SysUserRole;
import com.whacos.modules.system.service.FileService;
import com.whacos.modules.system.service.SysUserService;
import com.whacos.modules.system.vo.FileVO;
import com.whacos.modules.system.vo.SysUserVO;
import org.apache.commons.lang.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author xiongdun
 * @description SysDeptServiceImpl
 * @since 2018/11/17 17:11
 */
@CacheConfig(cacheNames = "sysUserCache")
@Transactional
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserDao, SysUser> implements SysUserService {

    @Autowired
    private SysUserDao sysUserDao;
    @Autowired
    private SysUserPlusDao sysUserPlusDao;
    @Autowired
    private SysUserRoleDao sysUserRoleDao;
    @Autowired
    private SysDeptDao sysDeptDao;
    @Autowired
    private FileService fileService;

    @Cacheable(key = "#id")
    @Override
    public SysUser getById(Serializable id) {
        List<Long> roleIds = this.sysUserRoleDao.listRoleId(id);
        SysUser sysUser = sysUserDao.selectById(id);
        sysUser.setDeptName(sysDeptDao.selectById(sysUser.getDeptId()).getDeptName());
        sysUser.setRoleIds(roleIds);
        return sysUser;
    }

    @Cacheable(key = "#id")
    @Override
    public String getUserName(Long id) {
        SysUser sysUser = sysUserDao.selectById(id);
        if (ObjectUtils.isNotEmpty(sysUser)) {
            return sysUser.getUsername();
        }
        return "admin";
    }

    @Override
    public SysUser get(String loginName) {
        if (StringUtils.isEmpty(loginName)) {
            throw new BDException("登录名不能为空！");
        }

        SysUser sysUser = new SysUser();
        if (StringUtils.isEmail(loginName)) {
            sysUser.setEmail(loginName);
        } else if (StringUtils.isMobileNumber(loginName)) {
            sysUser.setMobilePhone(loginName);
        } else if (StringUtils.isIdcard(loginName)) {
            sysUser.setIdCard(loginName);
        } else {
            sysUser.setUsername(loginName);
        }

        List<SysUser> sysUserList = this.list(Wrappers.lambdaQuery(new SysUser())
                .eq(StringUtils.isNotEmpty(sysUser.getUsername()), SysUser::getUsername, loginName)
                .eq(StringUtils.isNotEmpty(sysUser.getEmail()), SysUser::getEmail, loginName)
                .eq(StringUtils.isNotEmpty(sysUser.getMobilePhone()), SysUser::getMobilePhone, loginName)
                .eq(StringUtils.isNotEmpty(sysUser.getIdCard()), SysUser::getIdCard, loginName));
        if (ObjectUtils.isNotEmpty(sysUserList)) {
            return sysUserList.get(0);
        }

        return null;
    }

    @CacheEvict
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean save(SysUser sysUser) {
        sysUser.setPassword(MD5Utils.encrypt(sysUser.getUsername(), sysUser.getPassword()));
        sysUser.createdData(ShiroUtils.getUserId());
        int result = sysUserDao.insert(sysUser);
        if (result > 0) {
            // 按userId 删除用户与角色关联表信息
            result = sysUserRoleDao.delete(new LambdaQueryWrapper<SysUserRole>()
                    .eq(SysUserRole::getUserId, sysUser.getId()));

            if (ObjectUtils.isNotEmpty(sysUser.getRoleIds())) {
                result = this.batchSave(sysUser.getRoleIds(), sysUser.getId());
            }
        }
        return result > 0;
    }

    @Cacheable(key = "#sysUser.id")
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateById(SysUser sysUser) {
        sysUser.updatedData(ShiroUtils.getUserId());
        int result = sysUserDao.updateById(sysUser);
        if (result > 0) {
            // 按userId 删除用户与角色关联表信息
            result = sysUserRoleDao.delete(new LambdaQueryWrapper<SysUserRole>()
                    .eq(SysUserRole::getUserId, sysUser.getId()));

            if (ObjectUtils.isNotEmpty(sysUser.getRoleIds())) {
                result = this.batchSave(sysUser.getRoleIds(), sysUser.getId());
            }
        }
        return result > 0;
    }

    private int batchSave(List<Long> roles, Long userId) {
        List<SysUserRole> sysUserRoleList = new ArrayList<>();
        for (Long roleId : roles) {
            SysUserRole sysUserRole = new SysUserRole();
            sysUserRole.setUserId(userId);
            sysUserRole.setRoleId(roleId);
            sysUserRoleList.add(sysUserRole);
        }
        int result = 0;
        if (sysUserRoleList.size() > 0) {
            // 批量保存
            result = sysUserRoleDao.batchInsert(sysUserRoleList);
        }
        return result;
    }

    @CacheEvict
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean removeById(Serializable id) {
        int result = sysUserRoleDao.delete(new LambdaQueryWrapper<SysUserRole>()
                .eq(SysUserRole::getUserId, id));
        sysUserDao.deleteById(id);
        return result > 0;
    }

    @Override
    public boolean exist(SysUser sysUser) {
        boolean isExist = false;
        if (ObjectUtils.isNotEmpty(this.get(sysUser.getUsername()))) {
            isExist = true;
        }
        return isExist;
    }

    @Override
    public int resetPassword(SysUserVO sysUserVO, SysUser sysUser) throws Exception {
        if (Objects.equals(sysUserVO.getSysUser().getId(), sysUser.getId())) {
            if (Objects.equals(MD5Utils.encrypt(sysUser.getUsername(), sysUserVO.getPwdOld()), sysUser.getPassword())) {
                sysUser.setPassword(MD5Utils.encrypt(sysUser.getUsername(), sysUserVO.getPwdNew()));
                return sysUserDao.updateById(sysUser);
            } else {
                throw new Exception("输入的旧密码有误！");
            }
        } else {
            throw new Exception("你修改的不是你登录的账号！");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int adminResetPassword(SysUserVO sysUserVO) throws Exception {
        SysUser sysUser = this.getById(sysUserVO.getSysUser().getId());
        if ("admin".equals(sysUser.getUsername())) {
            throw new Exception("超级管理员的账号不允许直接重置！");
        }
        sysUser.setPassword(MD5Utils.encrypt(sysUser.getUsername(), sysUserVO.getPwdNew()));
        return this.sysUserDao.updateById(sysUser);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean batchRemove(List<Long> userIds) {
        int result = this.sysUserDao.deleteBatchIds(userIds);

        this.sysUserRoleDao.delete(new LambdaQueryWrapper<SysUserRole>()
                .in(SysUserRole::getUserId, userIds));

        return result > 0;
    }

    @Override
    public Tree<SysDept> getDeptTree() {
        List<Tree<SysDept>> treeList = new ArrayList<>();
        List<SysDept> sysDeptList = sysDeptDao.selectList(null);
        Long[] parentDepts = sysDeptDao.listParentDept();
        Long[] uDepts = this.sysUserDao.listAllDept();
        Long[] allDepts = (Long[]) ArrayUtils.addAll(parentDepts, uDepts);
        for (SysDept sysDept : sysDeptList) {
            if (!ArrayUtils.contains(allDepts, sysDept.getId())) {
                continue;
            }
            Tree<SysDept> treeSysDept = new Tree<>();
            treeSysDept.setId(sysDept.getId().toString());
            treeSysDept.setParentId(sysDept.getParentId().toString());
            treeSysDept.setText(sysDept.getDeptName());
            Map<String, Object> state = new HashMap<>();
            state.put("opened", true);
            state.put("mType", "dept");
            treeSysDept.setState(state);
            treeList.add(treeSysDept);
        }
        List<SysUser> users = this.sysUserDao.selectList(null);
        for (SysUser sysUser : users) {
            Tree<SysDept> treeSysDept = new Tree<>();
            treeSysDept.setId(sysUser.getId().toString());
            treeSysDept.setParentId(sysUser.getDeptId().toString());
            treeSysDept.setText(sysUser.getRealName());
            Map<String, Object> state = new HashMap<>();
            state.put("opened", true);
            state.put("mType", "user");
            treeSysDept.setState(state);
            treeList.add(treeSysDept);
        }
        // 默认顶级菜单为０，根据数据库实际情况调整
        return BuildTree.build(treeList);
    }

    @Override
    public int updatePersonal(SysUser sysUser) {
        return sysUserDao.updateById(sysUser);
    }

    @Override
    public FileVO updatePersonalImage(MultipartFile file, String avatarData, Long userId) throws Exception {
        String fileName = file.getOriginalFilename();

        if (StringUtils.isEmpty(fileName)) {
            return null;
        }

        fileName = FileUtils.renameToUUID(fileName);
        //获取图片后缀
        String prefix = fileName.substring((fileName.lastIndexOf(".") + 1));
        String[] str = avatarData.split(",");
        //获取截取的x坐标
        int x = (int) Math.floor(Double.parseDouble(str[0].split(":")[1]));
        //获取截取的y坐标
        int y = (int) Math.floor(Double.parseDouble(str[1].split(":")[1]));
        //获取截取的高度
        int h = (int) Math.floor(Double.parseDouble(str[2].split(":")[1]));
        //获取截取的宽度
        int w = (int) Math.floor(Double.parseDouble(str[3].split(":")[1]));
        //获取旋转的角度
        int r = Integer.parseInt(str[4].split(":")[1].replaceAll("}", ""));
        try {
            BufferedImage cutImage = ImageUtils.cutImage(file, x, y, w, h, prefix);
            BufferedImage rotateImage = ImageUtils.rotateImage(cutImage, r);
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            /*boolean flag = ImageIO.write(rotateImage, prefix, out);
            //转换后存入数据库
            byte[] b = out.toByteArray();
            FileUtils.uploadFile(b, whacosConfig.getUploadPath(), fileName);*/
        } catch (Exception e) {
            throw new Exception("图片裁剪错误！！");
        }
        FileVO fileVO = fileService.uploadFile(userId, file);
        if (fileVO.getResult() > 0) {
            SysUser sysUser = new SysUser();
            sysUser.setId(userId);
            sysUser.setAvatarId(fileVO.getId());
            this.sysUserDao.updateById(sysUser);

        }
        return fileVO;
    }

}
